fi
}
+handle_signal() {
+ local notify_op=$1
+ local label_op=$2
+ wait_notify() {
+ # wait for acme.sh child job to die, *then* notify about status
+ wait
+ log warn "$label_op aborted: $main_domain"
+ $NOTIFY "${notify_op}-failed"
+ exit 1
+ }
+
+ trap wait_notify TERM
+ # try to kill the cgroup
+ local cgroup=$(cut -d : -f 3 /proc/$$/cgroup)
+ if [[ "$cgroup" == '/services/acme/*' ]]; then
+ # send SIGTERM to all processes in this process's cgroup. this
+ # relies on procd's having set up the cgroup for the instance.
+ read -r -d '' pids < /sys/fs/cgroup${cgroup}/cgroup.procs
+ kill -TERM $pids 2> /dev/null
+ fi
+
+ # if we're here, either the cgroup wasn't as exected to be set up by
+ # procd or killing the cgroup PIDs failed. try to kill the process
+ # group, assuming this process is the group leader. this is actually
+ # unlikely since procd doesn't set service PGIDs (so they aren't group
+ # leaders).
+ kill -TERM -$$ 2> /dev/null
+
+ # if we're here, cgroup-based killing was avoided or didn't work and
+ # PGID-based killing didn't work. fall back to the raciest option.
+ trap "" TERM
+ term_descendants() {
+ local pids=$@
+ local pid=
+ # `pgrep -P` returns nothing if given a non-existent PID
+ # (even if the PID has live children), so children must
+ # be killed first
+ for pid in $pids; do
+ term_descendants $(pgrep -P "$pid")
+ kill -TERM "$pid" 2> /dev/null
+ done
+ }
+ term_descendants $(jobs -p)
+
+ wait_notify
+}
+
case $1 in
get)
set --
else
set -- "$@" --renew --home "$state_dir" -d "$main_domain"
log info "$ACME $*"
- trap 'log err "Renew failed: SIGINT";$NOTIFY renew-failed;exit 1' INT
- $ACME "$@"
+ trap "handle_signal renew Renewal" INT TERM
+ $ACME "$@" &
+ wait $!
status=$?
- trap - INT
+ trap - INT TERM
case $status in
0)
set -- "$@" --issue --home "$state_dir"
log info "$ACME $*"
- trap 'log err "Issue failed: SIGINT";$NOTIFY issue-failed;exit 1' INT
+ trap "handle_signal issue Issuance" INT TERM
"$ACME" "$@" \
--pre-hook "$NOTIFY prepare" \
- --renew-hook "$NOTIFY renewed"
+ --renew-hook "$NOTIFY renewed" &
+ wait $!
status=$?
- trap - INT
+ trap - INT TERM
case $status in
0)
# shellcheck source=net/acme/files/functions.sh
. "$IPKG_INSTROOT/usr/lib/acme/functions.sh"
-extra_command "renew" "Start a certificate renew"
+extra_command "abort" "Abort running certificate issuances/renewals"
+extra_command "renew" "Run certificate issuances/renewals"
delete_nft_rule() {
if [ "$NFT_HANDLE" ]; then
load_options "$section"
load_credentials() {
+ # use `eval` to correctly strip quotes around credential values
eval procd_append_param env "$1"
}
config_list_foreach "$section" credentials load_credentials
}
service_started() {
- echo "Certificate renewal enabled via cron. To renew now, run '/etc/init.d/acme renew'."
+ echo 'Nightly certificate renewal enabled. To renew now, run `service acme renew`.'
}
stop_service() {
sed -i '\|/etc/init.d/acme|d' /etc/crontabs/root
+ running && stop_aborted="Running certificate renewal(s) aborted and a"
}
service_stopped() {
- echo "Certificate renewal is disabled."
+ if enabled; then
+ untilboot=' until next boot. To disable permanently, run `service acme disable`'
+ fi
+ echo "${stop_aborted:-A}utomatic nightly renewal disabled$untilboot."
+ echo 'To re-enable nightly renewal, run `service acme start`. To issue/renew now, run `service acme renew`.'
}
service_triggers() {
}
renew() {
+ echo "Starting certificate issuance/renewal in the background; see system log for progress."
+ echo 'Issuances/renewals can be aborted with `service acme abort`.'
rc_procd load_and_run
}
+
+abort() {
+ procd_lock
+ if running "$@"; then
+ procd_kill "$(basename ${basescript:-$initscript})" "$1"
+ echo "Aborting certificate issuance(s)/renewal(s); see system log for confirmation."
+ elif [ -z "$1" ]; then
+ echo "No certificate issuances/renewals running to abort!"
+ exit 1
+ else
+ echo "No certificate issuance/renewal \"$1\" running to abort!"
+ exit 1
+ fi
+}